package com.concurrent.aqs;

import com.concurrent.annotations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author: zhouyang
 * @descrpition: ReentrantReadWriteLock使用读写锁 但是读写锁可能产生饥饿 使用于特定场景
 * 还有一个锁是StampLock 分乐观锁和悲观锁 可以大幅度提升性能和吞吐量
 * @time: 2019-05-09 18:20
 */
@Slf4j
@ThreadSafe
public class ReentrantReadWriteLockTest {
    //请求总数
    public static int clientTotal = 5000;

    private static ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    private static ReentrantReadWriteLock.ReadLock readLock = lock.readLock();

    private static ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();

    //请求并行的线程数
    public static int threadTotal = 200;

    private static Map<Integer,Integer> map = new HashMap<>();

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Semaphore semaphore = new Semaphore(threadTotal);
        for(int i=0;i<clientTotal;++i){
            final int now = i;
            executorService.execute(()->{
                try {
                    semaphore.acquire();
                    if(now % 3 == 0){
                        put(now,now);
                        log.info("当前map总值为{}",getAllKeys());
                    }else{
                        Integer g = get(now-10);
                        if(g == null){
                            log.info("当前线程{}，此时得到空值",now);
                        }else {
                            log.info("当前线程{}，此时得到{}",now,g.toString());
                        }

                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    semaphore.release();
                }
            });
        }
        executorService.shutdown();
    }

    private static void put(int key,int val) {
        writeLock.lock();
        try {
            map.put(key,val);
            log.info("map写入一个[{}]",key);
        }finally {
            writeLock.unlock();
        }
    }

    private static Integer get(int key){
        readLock.lock();
        try {
            return map.get(key);
        }finally {
            readLock.unlock();
        }
    }

    private static int getAllKeys(){
        readLock.lock();
        try {
            return map.size();
        }finally {
            readLock.unlock();
        }
    }
}
